package cn.yx.common.core.util.http.httpclient;

import cn.yx.common.core.enums.CharsetEnum;
import cn.yx.common.core.enums.MimeTypeEnum;
import cn.yx.common.core.exception.CommonException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.util.Map;

/**
 * <p>HttpPut操作类</p>
 * <p>封装了部分可直接调用的put方法，如果没有合适的put方法，则可以调用buildPut方法获得HttpPut对象后，再调用sendPut方法。</p>
 *
 * @author Wgssmart
 */
@Slf4j
public class HttpPutUtil extends HttpBasic {

    /**
     * 提交json格式数据到指定url
     *
     * @param url  url,可包含查询字符中
     * @param json json格式的字符串数据
     * @return 指定url响应的字符串数据
     */
    public static String putJson(String url, String json) {
        return put(url, json, MimeTypeEnum.JSON);
    }

    /**
     * 提交json格式数据到指定url
     *
     * @param url     url,可包含查询字符中
     * @param headers headers头部
     * @param json    json格式的字符串数据
     * @return 指定url响应的字符串数据
     */
    public static String putJson(String url, Map<String, String> headers, String json) {
        return put(url, headers, json, MimeTypeEnum.JSON);
    }

    /**
     * 通过指定的数据类型把数据put提交到指定的url
     *
     * @param url          url，可以包含查询字符串
     * @param data         需要提交的数据
     * @param dataTypeEnum 提交数据的MIME type
     * @return 指定url响应的字符串数据
     */
    public static String put(String url, String data, MimeTypeEnum dataTypeEnum) {
        return sendPut(buildHttpPut(url, null, data, dataTypeEnum), STRING_RESPONSE_HANDLER);
    }

    /**
     * 通过指定的数据类型把数据put提交到指定的url
     *
     * @param headers      headers头部
     * @param url          url，可以包含查询字符串
     * @param
     * @param data         需要提交的数据
     * @param dataTypeEnum 提交数据的MIME type
     * @return 指定url响应的字符串数据
     */
    public static String put(String url, Map<String, String> headers, String data, MimeTypeEnum dataTypeEnum) {
        return sendPut(buildHttpPut(url, headers, data, dataTypeEnum), STRING_RESPONSE_HANDLER);
    }

    /**
     * 构建http put请求
     *
     * @param url          请求url
     * @param headers      headers头部
     * @param data         请求的字符串数据，如json或xml
     * @param dataTypeEnum 指定请求的数据类型
     * @return
     */
    public static HttpPut buildHttpPut(String url, Map<String, String> headers, String data, MimeTypeEnum dataTypeEnum) {
        HttpPut httpPut = new HttpPut(url);
        refreshHeaders(headers, dataTypeEnum);
        setHeaders(httpPut, headers);
        httpPut.setEntity(new StringEntity(data, CharsetEnum.UTF8.getValue()));
        return httpPut;
    }

    /**
     * 发送HTTP PUT请求，并且需要指定相应的ResponseHandler
     *
     * @param httpPut         HttpPut请求
     * @param responseHandler ResponseHandler响应处理对象
     * @param <T>             响应处理对象中可通过泛型来指定返回的具体数据类型
     * @return 通过在ResponseHandler中指定的具体类型来返回响应数据
     */
    public static <T> T sendPut(HttpPut httpPut, ResponseHandler<T> responseHandler) {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            return executePut(httpClient, httpPut, responseHandler);
        } catch (IOException e) {
            log.error("http client execute put error: {}", e.getMessage());
            // @SimplifiedChinese=HTTP PUT请求失败
            // @English=Http Put error
            throw new CommonException("cn.yx.common.core.executeHttpPutError", e);
        }
    }

    /**
     * 执行http put请求
     *
     * @param httpClient
     * @param httpPut
     * @param responseHandler
     * @param <T>
     * @return
     */
    private static <T> T executePut(HttpClient httpClient, HttpPut httpPut, ResponseHandler<T> responseHandler) {
        try {
            httpPut.setConfig(requestConfig);
            return httpClient.execute(httpPut, responseHandler);
        } catch (IOException e) {
            log.error("http client execute put error: {}", e.getMessage());
            throw new CommonException("cn.yx.common.core.executeHttpPutError", e);
        }
    }

}
